package router

import (
	"fmt"
	"gdshop-admin-go-api/library/response"
	toolsDb "gdshop-admin-go-api/library/tools/db"
	"gdshop-admin-go-api/library/tools/token"
	version "gdshop-admin-go-api/library/tools/version"
	"github.com/gogf/gf/frame/g"
	"github.com/gogf/gf/net/ghttp"
	"reflect"
	"regexp"
	"strings"
	"time"
)

// 调用方法
func methodCall(r *ghttp.Request, version string, controller interface{}, methodName string) *response.JsonResponse {
	t := reflect.ValueOf(controller)
	// 获取当前需要执行的方法
	currentMethod := t.MethodByName(methodName)
	// 判断方法是否存在
	if !currentMethod.IsValid() {
		// 清除输出的信息
		r.Response.ClearBuffer()
		return response.FailByRequestMessage(r, version+" 不存在该方法，请确认后重新提交")
	}
	// 执行的参数，既是 请求
	args := []reflect.Value{reflect.ValueOf(r)}
	// 前置方法
	initMethod := t.MethodByName("Init")
	if initMethod.IsValid() {
		jieguo := initMethod.Call(args)[0].Interface().(*response.JsonResponse)
		if jieguo.Code != 0 {
			return jieguo
		}
	}
	// 执行当前URL方法
	jsonResp := currentMethod.Call(args)[0].Interface().(*response.JsonResponse)
	jsonResp.Version = version
	//r.Response.WriteJson(jsonResp)
	// 后置方法
	shutMethod := t.MethodByName("Shut")
	if shutMethod.IsValid() {
		jieguo := shutMethod.Call(args)[0].Interface().(*response.JsonResponse)
		if jieguo.Code != 0 {
			// 清除输出的信息
			r.Response.ClearBuffer()
			return jieguo
		}
	}
	// 返回执行方法
	return jsonResp
}

// BindHandlerVersion 绑定处理方法和版本
func BindHandlerVersion(r *ghttp.Request, versionName string,
	controllerMaps map[string]interface{},
	defaultVersionName string, methodName string) {

	var jsonResp *response.JsonResponse
	var versionVal string
	// 如果 controllerMaps 赋值长度只有一个，直接调用
	if len(controllerMaps) == 1 {
		versionVal = "1.0.0"
		jsonResp = methodCall(r, defaultVersionName, controllerMaps[defaultVersionName], methodName)
	} else {
		versionVal = version.GetVersion(r, versionName)
		// 如果未传 version ，则使用默认的版本
		if versionVal == "" {
			versionVal = defaultVersionName
		}
		//
		controller, exists := controllerMaps[versionVal]
		if !exists {
			// 不存在版本，使用默认版本
			controller, exists := controllerMaps[defaultVersionName]
			if !exists {
				response.JsonExit(r, 1, "版本不存在并且默认版本也不存在")
			} else {
				r.Header.Add(versionName, defaultVersionName)
				// 使用默认版本传入
				jsonResp = methodCall(r, defaultVersionName, controller, methodName)
			}
			return
		} else {
			jsonResp = methodCall(r, versionVal, controller, methodName)
		}
	}

	// 日志
	if strings.Index(r.Request.URL.Path, "/upload") == -1 {
		// 写请求日志，根据配置
		if g.Cfg().GetBool("site.RequestLogIsOpen") {
			addReqLog(r, r.Request.URL.Path, versionVal, jsonResp)
		}
	}
	// 根据URL处理缓存，自动清除缓存
	claerCacheByUrl(r.Request.URL.Path)

	err := r.Response.WriteJsonExit(jsonResp)
	if err != nil {
		return
	}
}

// 写日志，暂时不记录返回数据
func addReqLog(r *ghttp.Request, path, version string, jsonResp *response.JsonResponse) {
	/*returnData, err := json.Marshal(jsonResp)
	jsonText := ""
	if err != nil {
		jsonText = "json err"
	} else {
		jsonText = string(returnData)
	}*/
	if strings.Index(path, "/gdshop/open/captcha") != -1 {
		return
	}
	_, _ = toolsDb.GetUnSafaTableAddDeleteWhere(r.GetCtx(), "app_request_log").Insert(g.Map{
		"user_id":    token.GetLoginMemberId(r),
		"request_id": r.GetCtxVar("trace_id"),
		"route":      path,
		//"header_data" : r.GetCtxVar("trace_id"),
		"param_data": r.GetBodyString(),
		//"return_data": jsonText,
		"version": version,
		"ip":      r.GetRemoteIp(),
		"in_at":   time.Now().UnixNano() / 1e6,
	})
}

// 注册基础方法
func regBase(apis []string, group *ghttp.RouterGroup, controllerMaps map[string]interface{}, versionName,
	defaultVersionName string) {
	for _, apiName := range apis {
		switch apiName {
		case "add":
			group.POST("/"+apiName, func(r *ghttp.Request) {
				BindHandlerVersion(r, versionName, controllerMaps, defaultVersionName,
					"Add")
			})
			break
		case "update":
			group.POST("/update", func(r *ghttp.Request) {
				BindHandlerVersion(r, versionName, controllerMaps, defaultVersionName,
					"Update")
			})
			break
		case "delete":
			group.POST("/delete", func(r *ghttp.Request) {
				BindHandlerVersion(r, versionName, controllerMaps, defaultVersionName,
					"Delete")
			})
			break
		case "info":
			group.GET("/info", func(r *ghttp.Request) {
				BindHandlerVersion(r, versionName, controllerMaps, defaultVersionName,
					"Info")
			})
			break
		case "list":
			group.POST("/list", func(r *ghttp.Request) {
				BindHandlerVersion(r, versionName, controllerMaps, defaultVersionName,
					"List")
			})
			break
		case "page":
			group.POST("/page", func(r *ghttp.Request) {
				BindHandlerVersion(r, versionName, controllerMaps, defaultVersionName,
					"Page")
			})
			break
		}
	}
}

var claerCacheUrls = map[string]string{
	//`^/gdshop/admin/update` : "adminCache:*",
	`^/gdshop/role/add`:           "adminCache:*",
	`^/gdshop/role/update`:        "adminCache:*",
	`^/gdshop/role/delete`:        "adminCache:*",
	`^/gdshop/menu/add`:           "adminCache:*",
	`^/gdshop/menu/update`:        "adminCache:*",
	`^/gdshop/menu/delete`:        "adminCache:*",
	`^/gdshop/admin/personUpdate`: "adminCache:*",
}

func claerCacheByUrl(url string) {
	for k, item := range claerCacheUrls {
		reg1 := regexp.MustCompile(k)
		result1 := reg1.FindAllStringSubmatch(url, -1)
		if len(result1) > 0 {
			doVar, err := g.Redis().DoVar("keys", item)
			if err != nil {
				fmt.Println(err)
				return
			}
			g.Redis().Do("del", doVar.Array()...)
		}
	}
}
